package com.devilvan.betrice.jpxgmn.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devilvan.betrice.annotation.BetriceRunTime;
import com.devilvan.betrice.common.BetriceResultVo;
import com.devilvan.betrice.download.component.BetriceDownloadComponent;
import com.devilvan.betrice.download.pojo.PictureSuffixConstant;
import com.devilvan.betrice.exception.BetriceException;
import com.devilvan.betrice.jpxgmn.common.JpxgmnConstant;
import com.devilvan.betrice.jpxgmn.dto.FindPageByJpxgmnDownloadDto;
import com.devilvan.betrice.jpxgmn.dto.JpxgmnHeaderDto;
import com.devilvan.betrice.jpxgmn.entity.FindPageByJpxgmnDownloadEntity;
import com.devilvan.betrice.jpxgmn.entity.JpxgmnDownloadEntity;
import com.devilvan.betrice.jpxgmn.po.JpxgmnDetailPo;
import com.devilvan.betrice.jpxgmn.po.JpxgmnHeaderPo;
import com.devilvan.betrice.jpxgmn.service.JpxgmnDetailService;
import com.devilvan.betrice.jpxgmn.service.JpxgmnHeaderService;
import com.devilvan.betrice.jpxgmn.mapper.JpxgmnHeaderMapper;
import com.devilvan.betrice.jpxgmn.repository.JpxgmnHeaderRepository;
import com.devilvan.betrice.jpxgmn.vo.JpxgmnDownloadVo;
import com.devilvan.betrice.jpxgmn.vo.JpxgmnHeaderVo;
import com.devilvan.betrice.request.component.HttpClientComponent;
import com.devilvan.betrice.request.component.JsoupComponent;
import com.devilvan.betrice.util.UString;
import com.devilvan.betrice.util.UCopy;
import com.devilvan.betrice.util.UValidAssem;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Evad.Wu
 * @Description JPXGMN-头信息表 业务逻辑类
 * @date 2022-11-16
 */
@Service
public class JpxgmnHeaderServiceImpl extends ServiceImpl<JpxgmnHeaderMapper, JpxgmnHeaderPo> implements JpxgmnHeaderService {
    private final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    @Resource(name = "jsoupComponent")
    private JsoupComponent jsoupComponent;
    @Resource(name = "betriceDownloadComponent")
    private BetriceDownloadComponent betriceDownloadComponent;
    @Resource(name = "httpClientComponent")
    private HttpClientComponent httpClientComponent;
    @Resource(name = "transactionTemplate")
    private TransactionTemplate transactionTemplate;
    @Resource(name = "threadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource(name = "jpxgmnHeaderRepository")
    private JpxgmnHeaderRepository jpxgmnHeaderRepository;
    @Resource(name = "jpxgmnHeaderMapper")
    private JpxgmnHeaderMapper jpxgmnHeaderMapper;
    @Resource(name = "jpxgmnDetailServiceImpl")
    private JpxgmnDetailService jpxgmnDetailService;

    @Override
    @BetriceRunTime
    @Async(value = "threadPoolExecutor")
    public CompletableFuture<BetriceResultVo<JpxgmnHeaderPo>> doJpxgmnHeaderRequest(String url, String keyword, Map<String, String> subHeader) {
        BetriceResultVo<JpxgmnHeaderPo> betriceResultVo = new BetriceResultVo<>();
        // 通过完整URL提取出对应的枚举类型
        JpxgmnConstant jpxgmnConstant = JpxgmnConstant.getInstanceByUrlPrefix(url);
        subHeader.put("referer", jpxgmnConstant.getUrl());
        String httpGetParamUrl = UString.generateHttpParamUrl(url, Map.of("keyword", keyword));
        Element body = jsoupComponent.getBody(httpGetParamUrl, subHeader);
        // 关键字查询结果总页码
        Elements totalPage = body.select("div.pagination:nth-child(2)>ul>a");
        System.out.println("总页数：" + totalPage.size());
        for (Element pageElem : totalPage) {
            Integer currentPage = Integer.parseInt(pageElem.text());
            String currentLink = url + pageElem.attr("href");
            System.out.println(currentLink);
            Element innerBody = jsoupComponent.getBody(currentLink, subHeader);
            assert innerBody != null;
            Elements rows = innerBody.select("div.node>p>a");
            Elements infoList = innerBody.select("div.node>div.info>span:nth-child(1)");
            List<JpxgmnHeaderVo> jpxgmnHeaderVoList = new ArrayList<>();
            for (int j = 0; j < rows.size(); j++) {
                Element row = rows.get(j);
                String href = row.attr("href");
                String title = row.text();
                String pid = href.substring(href.lastIndexOf("/")).replace(".html", "");
                JpxgmnHeaderVo jpxgmnHeaderVo = new JpxgmnHeaderVo();
                jpxgmnHeaderVo.setUrl(jpxgmnConstant.getUrl() + href);
                jpxgmnHeaderVo.setPid(pid);
                jpxgmnHeaderVo.setTitle(title);
                jpxgmnHeaderVo.setName(keyword);
                jpxgmnHeaderVo.setPageNum(currentPage);
                try {
                    jpxgmnHeaderVo.setPmodifyTime(SIMPLE_DATE_FORMAT.parse(infoList.get(j).text()));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                jpxgmnHeaderVoList.add(jpxgmnHeaderVo);
            }
            jpxgmnHeaderVoList.forEach(System.out::println);
            List<JpxgmnHeaderDto> jpxgmnHeaderDtoList = UCopy.fullCopyCollections(jpxgmnHeaderVoList, JpxgmnHeaderDto.class);
            this.saveUpdateBatch(jpxgmnHeaderDtoList);
        }
        return CompletableFuture.completedFuture(betriceResultVo);
    }

    @Override
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public BetriceResultVo<List<JpxgmnDownloadEntity>> doJpxgmnDetailDownloadScheduler(JpxgmnDownloadVo jpxgmnDownloadVo) {
        BetriceResultVo<List<JpxgmnDownloadEntity>> betriceResultVo = new BetriceResultVo<>();
        // D:\\Mine\\杂物\\
        String exportPath = Optional.ofNullable(jpxgmnDownloadVo.getExportPath())
                .orElseThrow(() -> new BetriceException("导出路径不能为空！"));
        exportPath = exportPath.endsWith("\\") ? exportPath : exportPath + "\\";
        String suffix = PictureSuffixConstant.getInstanceBySuffix(jpxgmnDownloadVo.getSuffix()).getValue();
        // 根据条件查询
        FindPageByJpxgmnDownloadDto findPageByJpxgmnDownloadDto = new FindPageByJpxgmnDownloadDto();
        UCopy.fullCopy(jpxgmnDownloadVo, findPageByJpxgmnDownloadDto);
        Page<FindPageByJpxgmnDownloadEntity> page = new Page<>(1, 100);
        Page<FindPageByJpxgmnDownloadEntity> findByJpxgmnDownloadEntityPage = jpxgmnHeaderMapper.findByJpxgmnDownloadDto(findPageByJpxgmnDownloadDto, page);
        List<FindPageByJpxgmnDownloadEntity> downloadEntityList = findByJpxgmnDownloadEntityPage.getRecords();
        // 启用屏障
        CountDownLatch countDownLatch = new CountDownLatch(downloadEntityList.size());
//        List<JpxgmnDownloadEntity> jpxgmnDownloadEntityList = new ArrayList<>();
        for (FindPageByJpxgmnDownloadEntity findPageByJpxgmnDownloadEntity : downloadEntityList) {
            String finalExportPath = exportPath;
            threadPoolExecutor.execute(() -> {
//                JpxgmnDownloadEntity jpxgmnDownloadEntity = new JpxgmnDownloadEntity();
                String name = findPageByJpxgmnDownloadEntity.getName();
                String dir = finalExportPath + findPageByJpxgmnDownloadEntity.getTitle();
                // 检查文件夹时加锁处理
                ReentrantLock rlock = new ReentrantLock();
                rlock.lock();
                try {
                    File fileDir = new File(dir);
                    fileDir.mkdirs();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    rlock.unlock();
                }
                // 配置完整输出路径
                String fileName = name + "-" + UUID.randomUUID();
                String completeExportPath = UValidAssem.validExportPath(dir, fileName, suffix);
                // 下载资源
                transactionTemplate.execute(status -> {
                    String picUrl = findPageByJpxgmnDownloadEntity.getUrl();
                    betriceDownloadComponent.download(httpClientComponent.generateHttpRequest(RequestMethod.GET, picUrl), completeExportPath);
                    // 是否已下载状态修改
                    findPageByJpxgmnDownloadEntity.setDownloaded(true);
                    return null;
                });
                // 整理回调对象
//                jpxgmnDownloadEntity.setExportPath(completeExportPath);
//                jpxgmnDownloadEntity.setFileName(fileName);
//                jpxgmnDownloadEntity.setSuffix(suffix);
//                jpxgmnDownloadEntityList.add(jpxgmnDownloadEntity);
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
            // 批量修改detail的状态
            List<JpxgmnDetailPo> jpxgmnDetailPoList = this.downloadEntity2JpxgmnDetailPoList(downloadEntityList);
            jpxgmnDetailService.updateBatch(jpxgmnDetailPoList);
//            betriceResultVo.result(BetriceResultCodeConstant.SUCCESS_200, "操作成功！", jpxgmnDownloadEntityList);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return betriceResultVo;
    }

    @Override
    public JpxgmnHeaderPo saveUpdate(JpxgmnHeaderDto jpxgmnHeaderDto) {
        JpxgmnHeaderPo jpxgmnHeaderPo = new JpxgmnHeaderPo();
        UCopy.fullCopy(jpxgmnHeaderDto, jpxgmnHeaderPo);
        return jpxgmnHeaderRepository.saveAndFlush(jpxgmnHeaderPo);
    }

    @Override
    public List<JpxgmnHeaderPo> saveUpdateBatch(List<JpxgmnHeaderDto> list) {
        List<JpxgmnHeaderPo> jpxgmnHeaderPoList = UCopy.fullCopyCollections(list, JpxgmnHeaderPo.class);
        return jpxgmnHeaderRepository.saveAllAndFlush(jpxgmnHeaderPoList);
    }

    @Override
    public JpxgmnHeaderPo findByPid(String pid) {
        LambdaQueryWrapper<JpxgmnHeaderPo> queryWrapper = new QueryWrapper<JpxgmnHeaderPo>().lambda();
        queryWrapper.eq(JpxgmnHeaderPo::getPid, pid);
        return this.getOne(queryWrapper);
    }

    private List<JpxgmnDetailPo> downloadEntity2JpxgmnDetailPoList(List<FindPageByJpxgmnDownloadEntity> downloadEntityList) {
        List<JpxgmnDetailPo> jpxgmnDetailPoList = new ArrayList<>();
        for (FindPageByJpxgmnDownloadEntity findPageByJpxgmnDownloadEntity : downloadEntityList) {
            JpxgmnDetailPo jpxgmnDetailPo = new JpxgmnDetailPo();
            jpxgmnDetailPo.setId(findPageByJpxgmnDownloadEntity.getDetailId());
            jpxgmnDetailPo.setRecVer(findPageByJpxgmnDownloadEntity.getRecVer());
            jpxgmnDetailPo.setDownloaded(findPageByJpxgmnDownloadEntity.getDownloaded());
            jpxgmnDetailPoList.add(jpxgmnDetailPo);
        }
        return jpxgmnDetailPoList;
    }
}
